'use strict';

// Content script file will run in the context of web page.
// With content script you can manipulate the web pages using
// Document Object Model (DOM).
// You can also pass information to the parent extension.

// We execute this script by making an entry in manifest.json file
// under `content_scripts` property

// For more information on Content Scripts,
// See https://developer.chrome.com/extensions/content_scripts

var SETTINGS = '___DATA_COPY:SETTINGS'

var $dataCopyStorage = {
  get: (key, cb) => {
    chrome.storage.local.get([key], result => {
      cb(result[key]);
    });
  },
  set: (key, value, cb) => {
    chrome.storage.local.set(
      {
        [key]: value,
      },
      () => {
        cb && cb();
      }
    );
  },
};

var $dataCopyData = {
  settings: {
    listenSite: '',
    listenStatus: '',
    source: [{
      selectorName: '', 
      storageKey: ''
    }],
    target: [{
      selectorName: '',
      storageKey: ''
    }]
  },
  source: {
    refreshDate: new Date(),
    settings: [{
      selectorName: '', 
      storageKey: '',
      domExist: false,
      value: undefined,
      autoSave: false, // 自动保存
    }]
  },
  target: {
    refreshDate: new Date(),
    settings: [{
      selectorName: '', 
      storageKey: '',
      domExist: false,
      value: undefined,
      targetValue: undefined
    }]
  }
}

// Listen for message
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
  if (request.type === 'getDomValue') {
    sendResponse(getDomValue(request.payload.selectorName, request.payload.type === 'target'));
  }

  if(request.type === 'setDomValue') {
    setDomValue(request.payload.selectorName, request.payload.value || '')
    sendResponse({});
  }

  if(request.type === 'getSourceDomValue') {
    $dataCopyStorage.get(SETTINGS, (settings)=> {
      $dataCopyData.settings = settings || {
        source: [],
        target: []
      }
      getSourceDomValue()
    })
  }
  
  if(request.type === 'setTargetDomValue') {


    $dataCopyStorage.get(SETTINGS, async (settings)=> {
      $dataCopyData.settings = settings || {
        source: [],
        target: []
      }

      // var continueFlag = await __RUN_CONTINUE()
      // if(!continueFlag) return;
      setTargetDomValue()
    })
  }

  return true;
});

function getSourceDomValue() {
  var listenSite = $dataCopyData.settings.listenSite || '';  if(!listenSite) return;

  var listenSiteUri = new URL(listenSite)
  var cucrentSiteUri = location

  if(listenSiteUri.host !== cucrentSiteUri.host) {
    return;
  }  

  var sourceArray = $dataCopyData.settings.source || []
  var settingsArray = []
  sourceArray.forEach((item)=> {
    var data = {
      selectorName: item.selectorName,
      storageKey: item.storageKey
    }
    var evt = getDomValue(item.selectorName)
    data.value = evt.value
    data.domExist = evt.domExist
    settingsArray.push(data)
    if(settingsArray.length === sourceArray.length) {
      $dataCopyData.source.settings = settingsArray
      autoCopy()
    }
  })
}

function getTargetDomValue(callback) {
  var targetArray = $dataCopyData.settings.target || []
  var settingsArray = []
  targetArray.forEach((item)=> {
    var data = {
      selectorName: item.selectorName,
      storageKey: item.storageKey
    }
    $dataCopyStorage.get(data.storageKey, (value)=> {
      data.targetValue = value
      var evt = getDomValue(item.selectorName)
      data.value = evt.value
      data.domExist = evt.domExist
      settingsArray.push(data)
  
      if(settingsArray.length === targetArray.length) {
        $dataCopyData.target.settings = settingsArray
        callback()
      }
    })
  })
}

async function delay(timeout) {
  return new Promise((resolve, _) => {
    setTimeout(()=> {
      resolve()
    }, timeout)
  })
}


function setTargetDomValue() {
  getTargetDomValue(()=> {
    var settins = $dataCopyData.target.settings || []
    settins.reduce((chain, item) => {
      return chain
        .then(()=> setDomValue(item.selectorName, item.targetValue, true))
        .then(()=> __RUN_SCRIPT.bind({
          ...item,
          delay: delay,
          setDomValue: setDomValue,
          getDomValue: getDomValue,
          getSelectorByStorageKey(storageKey) {
            return settins.find((it) => it.storageKey == storageKey)
          }
        })());
    }, Promise.resolve());
  })
}

function isVisible(dom) {
  return dom.getBoundingClientRect().width > 0 && dom.getBoundingClientRect().height > 0;
}

function querySelector(selectorName, onlyVisible = false) {
  if(!onlyVisible) {
    var dom = document.querySelector(selectorName)
    return dom
  }

  var doms = document.querySelectorAll(selectorName)
  console.log(doms, selectorName)

  for (let index = 0; index < doms.length; index++) {
    const element = doms[index];
    if(isVisible(element)) {
      console.log('isVisible', element, selectorName)
      return element
    }
  }
  return null
}

function getDomValue(selectorName, onlyVisible = false) {
  var dom = querySelector(selectorName, onlyVisible)
  return {
    value: dom ? (dom.value || dom.innerText) : undefined,
    domExist: !!dom
  }
}

async function setDomValue(selectorName, value, onlyVisible = false) {
  return new Promise((resolve)=> {
    var dom = querySelector(selectorName, onlyVisible)
    console.log(dom, selectorName, value)
    if(!dom) resolve()
    dom.dispatchEvent(new Event('focus', { bubbles: true }));
    setTimeout(async ()=> {
      dom.value = value || ''
      await delay(10)
      dom.dispatchEvent(new Event('input', { bubbles: true }));
      await delay(10)
      dom.dispatchEvent(new Event('change', { bubbles: true }));
      await delay(10)
      dom.dispatchEvent(new Event('blur', { bubbles: true }));
      resolve()
    }, 10)
  })
}

function autoCopy() {
  var settins = $dataCopyData.source.settings || []
  settins.forEach((item) => {
    $dataCopyStorage.set(item.storageKey, item.value)
  })
}

$dataCopyStorage.get(SETTINGS, (settings)=> {
  $dataCopyData.settings = settings || {
    source: [],
    target: []
  }
  getSourceDomValue()
})


window.$dataCopyStorage = $dataCopyStorage
window.$dataCopyData = $dataCopyData